﻿
Imports System.IO
Imports System.Net
Imports std
Imports xmlctrl
Imports httpContext

Public Class httpContext
    Public Class httpContextUrlParameters
        Public Const language As String = "setlang"
    End Class

    Public Class parameterDefinition
        Implements ICloneable

        Private _parseInputStream As Boolean
        Private _parseFDHeaders As Boolean
        Private _parseHttpContextUrlParameters As Boolean
        Private _parseCookies As Boolean
        Private _stringsPackage As stringsPackage = Nothing
        Private _enableGzip As Boolean

        Public Function parseInputStream() As Boolean
            Return _parseInputStream
        End Function

        Public Function parseFDHeaders() As Boolean
            Return _parseFDHeaders
        End Function

        Public Function parseHttpContextUrlParameters() As Boolean
            Return _parseHttpContextUrlParameters
        End Function

        Public Function parseCookies() As Boolean
            Return _parseCookies
        End Function

        Public Function stringsPackage() As stringsPackage
            Return _stringsPackage
        End Function

        Public Function enableGzip() As Boolean
            Return _enableGzip
        End Function

        Public Sub New(Optional ByVal parseInputStream As Boolean = True, _
                       Optional ByVal parseFDHeaders As Boolean = True, _
                       Optional ByVal parseHttpContextUrlParameters As Boolean = True, _
                       Optional ByVal parseCookies As Boolean = True, _
                       Optional ByVal stringsPackage As stringsPackage = Nothing, _
                       Optional ByVal enableGzip As Boolean = True)
            _parseInputStream = parseInputStream
            _parseFDHeaders = parseFDHeaders
            _parseHttpContextUrlParameters = parseHttpContextUrlParameters
            _parseCookies = parseCookies
            _stringsPackage = stringsPackage
            _enableGzip = enableGzip
        End Sub

        Public Function Clone() As Object Implements System.ICloneable.Clone
            Dim rtn As parameterDefinition = Nothing
            rtn = New parameterDefinition(parseInputStream(), parseFDHeaders(), _
                                          parseHttpContextUrlParameters(), parseCookies(), stringsPackage())

            Return rtn
        End Function
    End Class

    Public Const MAX_BUFF_CAPACITY As Int64 = 512 * 1024
    Public Shared ReadOnly MAX_READ_INPUTSTREAM_TIMEOUT_TICKS As Int64 = secondsToTicks(10 * 60)
    Public Shared ReadOnly defaultParameter As parameterDefinition = Nothing

    Shared Sub New()
        defaultParameter = New parameterDefinition()
    End Sub

    Private _paramter As parameterDefinition = Nothing
    Private _listenerContext As HttpListenerContext
    Private _buff As MemoryStream
    Private _request As HttpListenerRequest
    Private _response As HttpListenerResponse
    Private _writer As StreamWriter
    Private _closed As Boolean
    Private _url As url
    Private _userAgent As String
    Private _friendlyUserAgent As String
    Private _isBrowserUserAgent As Boolean
    Private _isIEUserAgent As Boolean
    Private _referer As String
    Private _contentType As String
    Private _friendlyReferer As String
    Private _requestIp As String
    Private _language As String
    Private _traceID As String
    Private _filters As map(Of String, String)
    Private _strings As strings = Nothing
    Private _formdatas As map(Of String, formdata) = Nothing
    Private _cookies As map(Of String, map(Of String, String)) = Nothing
    Private _isinternalRequest As ternary
    Private _rejectIssuesByte As Byte
    Private _rejectIssues As String
    Private _publicIps As vector(Of String)
    Private _acceptEncoding As String
    Private _acceptGzip As Boolean

    Public Function parameter() As parameterDefinition
        assert(Not _paramter Is Nothing, "should set _parameter before any operation.")
        Return _paramter
    End Function

    Private Sub clearfilters()
        If Not _filters Is Nothing Then
            _filters.clear()
        End If
    End Sub

    Private Sub clearformdatas()
        If Not _formdatas Is Nothing Then
            _formdatas.clear()
        End If
    End Sub

    Private Sub clearCookies()
        If Not _cookies Is Nothing Then
            _cookies.clear()
        End If
    End Sub

    Private Sub clearRejectIssues()
        _rejectIssuesByte = 0
        _rejectIssues = Nothing
    End Sub

    Public Function filters() As map(Of String, String)
        If _filters Is Nothing OrElse _filters.empty() Then
            If _filters Is Nothing Then
                _filters = New map(Of String, String)()
            End If
            _filters(filterNaming.host) = url.host()
            _filters(filterNaming.port) = Convert.ToString(url.port)
            _filters(filterNaming.userAgent) = userAgent()
            _filters(filterNaming.language) = language()
            _filters(filterNaming.referer) = referer()
            _filters(filterNaming.requestIp) = requestIp()
        ElseIf isdebugmode() Then
            assert(_filters(filterNaming.host) = url.host(), "forget to clear filters.")
            assert(_filters(filterNaming.port) = Convert.ToString(url.port), "forget to clear filters.")
            assert(_filters(filterNaming.userAgent) = userAgent(), "forget to clear filters.")
            assert(_filters(filterNaming.language) = language(), "forget to clear filters.")
            assert(_filters(filterNaming.referer) = referer(), "forget to clear filters.")
            assert(_filters(filterNaming.requestIp) = requestIp(), "forget to clear filters.")
        End If

        Return _filters
    End Function

    Public Function generatefilters() As map(Of String, String)
        Return filters()
    End Function

    Public Function setstatuscode(ByVal status As Int32, Optional ByVal description As String = emptyString) As Boolean
        Try
            response().StatusCode = status
            response().StatusDescription = description
        Catch ex As Exception
            raiseError("cannot set status code, message " + ex.Message, errorHandle.errorType.system)
            Return False
        End Try

        Return True
    End Function

    Public Function setcontentType(ByVal t As String) As Boolean
        Try
            response().ContentType = t
        Catch ex As Exception
            raiseError("cannot set contentType, message " + ex.Message, errorHandle.errorType.system)
            Return False
        End Try

        Return True
    End Function

    Public Function setcontentEncoding(ByVal e As Text.Encoding) As Boolean
        Try
            response().ContentEncoding = e
        Catch ex As Exception
            raiseError("cannot set contentEncoding, message " + ex.Message, errorHandle.errorType.system)
            Return False
        End Try

        Return True
    End Function

    Public Function setcontentLength64(ByVal len As Int64) As Boolean
        Try
            response().ContentLength64 = len
        Catch ex As Exception
            raiseError("cannot set contentLength64, message " + ex.Message, errorHandle.errorType.system)
            Return False
        End Try

        Return True
    End Function

    Public Function setcacheControl(ByVal enable As Boolean, Optional ByVal cacheticks As Int64 = npos) As Boolean
        Try
            If enable AndAlso cacheticks >= 0 Then
                response().Headers().Add(HttpResponseHeader.CacheControl _
                                         , network.http.headers.cachecontrol.max_age(cacheticks))
            Else
                response().Headers().Add(HttpResponseHeader.CacheControl, network.http.headers.cachecontrol.no_cache)
            End If
        Catch ex As Exception
            raiseError("cannot set cachecontrol, message " + ex.Message, errorHandle.errorType.system)
            Return False
        End Try

        Return True
    End Function

    Public Function redirect(ByVal url As String) As Boolean
        Try
            response().Redirect(url)
            close()
        Catch ex As Exception
            raiseError("cannot redirect to destination " + url + ", message " + ex.Message, errorHandle.errorType.system)
            Return False
        End Try

        Return True
    End Function

#If RETIRED Then
    Private Shared Function generateCookie(ByVal domain As String, ByVal path As String, ByVal name As String, _
                                    ByVal value As String, ByVal expires As DateTime) As Cookie
        Dim rtn As Cookie = Nothing
        rtn = New Cookie(name, value, path, domain)
        rtn.Expires = expires

        Return rtn
    End Function
#End If

    Public Function setcookie(ByVal domain As String, ByVal path As String, _
                              ByVal name As String, ByVal value As String, _
                              ByVal expires As DateTime) As Boolean
        If expires <> DateTime.MaxValue OrElse _
           cookie(cookieMap(domain, path)).find(name) = cookie(cookieMap(domain, path)).end() OrElse _
           Not strsame(cookie(cookieMap(domain, path))(name), value) Then
            If Not addheader(response().Headers, HttpResponseHeader.SetCookie, _
                             rfc2109.generateCookie(domain, path, name, value, expires)) Then
                raiseError("cannot set cookie name " + _
                           name + ", value " + value + ", path " + path + ", domain " + domain, _
                           errorHandle.errorType.system)
                Return False
            End If
        End If
        Return True
    End Function

    Public Function setsessioncookie(ByVal domain As String, ByVal path As String, _
                                     ByVal name As String, ByVal value As String) As Boolean
        Return setcookie(domain, path, name, value, DateTime.MinValue)
    End Function

    Public Function setforevercookie(ByVal domain As String, ByVal path As String, _
                                     ByVal name As String, ByVal value As String) As Boolean
        Return setcookie(domain, path, name, value, DateTime.MaxValue)
    End Function

    Public Function setcookie(ByVal path As String, ByVal name As String, ByVal value As String, _
                              ByVal expires As DateTime) As Boolean
        Return setcookie(Nothing, path, name, value, expires)
    End Function

    Public Function setsessioncookie(ByVal path As String, ByVal name As String, ByVal value As String) As Boolean
        Return setcookie(path, name, value, DateTime.MinValue)
    End Function

    Public Function setforevercookie(ByVal path As String, ByVal name As String, ByVal value As String) As Boolean
        Return setcookie(path, name, value, DateTime.MaxValue)
    End Function

    Public Function setcookie(ByVal name As String, ByVal value As String, _
                              ByVal expires As DateTime) As Boolean
        Return setcookie(Nothing, Nothing, name, value, expires)
    End Function

    Public Function setsessioncookie(ByVal name As String, ByVal value As String) As Boolean
        Return setcookie(name, value, DateTime.MinValue)
    End Function

    Public Function setforevercookie(ByVal name As String, ByVal value As String) As Boolean
        Return setcookie(name, value, DateTime.MaxValue)
    End Function

    Public Function addResponseHeader(ByVal header As HttpResponseHeader, ByVal value As String) As Boolean
        Return addheader(response().Headers(), header, value)
    End Function

    Public Function removeResponseHeader(ByVal header As HttpResponseHeader) As Boolean
        Return removeheader(response().Headers(), header)
    End Function

    Public Function modifyResponseHeader(ByVal header As HttpResponseHeader, ByVal value As String) As Boolean
        Return modifyheader(response().Headers(), header, value)
    End Function

    Public Function addResponseHeader(ByVal header As String, ByVal value As String) As Boolean
        Return addheader(response().Headers(), header, value)
    End Function

    Public Function removeResponseHeader(ByVal header As String) As Boolean
        Return removeheader(response().Headers(), header)
    End Function

    Public Function modifyResponseHeader(ByVal header As String, ByVal value As String) As Boolean
        Return modifyheader(response().Headers(), header, value)
    End Function

    Public Function buff() As MemoryStream
        assert(Not _buff Is Nothing AndAlso _buff.CanRead() AndAlso _buff.CanWrite() _
               , "_buff instance is released unexpectedly.")
        Return _buff
    End Function

    Public Function request() As HttpListenerRequest
        Return _request
    End Function

    Public Function response() As HttpListenerResponse
        Return _response
    End Function

    Public Function writer() As StreamWriter
        assert(Not _writer Is Nothing AndAlso Not _writer.BaseStream Is Nothing _
                , "_writer or _writer.BaseStream instance is released unexpectedly.")
        debugassert(_writer.BaseStream.CanRead AndAlso _writer.BaseStream.CanWrite, _
                    "_writer.BaseStream can not read or write.")
        Return _writer
    End Function

    Public Function url() As url
        Return _url
    End Function

    Public Function userAgent() As String
        Return _userAgent
    End Function

    Public Function isBrowserUserAgent() As Boolean
        Return _isBrowserUserAgent
    End Function

    Public Function isIEUserAgent() As Boolean
        Return _isIEUserAgent
    End Function

    Public Function friendlyUserAgent() As String
        Return _friendlyUserAgent
    End Function

    Public Function referer() As String
        Return _referer
    End Function

    Public Function friendlyReferer() As String
        Return _friendlyReferer
    End Function

    Public Function contentType() As String
        Return _contentType
    End Function

    Public Function requestIp() As String
        Return _requestIp
    End Function

    Public Function language() As String
        Return _language
    End Function

    Public Function closed() As Boolean
        Return _closed
    End Function

    Public Function traceID() As String
        Return _traceID
    End Function

    Public Function acceptEncoding() As String
        Return _acceptEncoding
    End Function

    Public Function acceptGzip() As Boolean
        Return _acceptGzip
    End Function

    'for diagnostic only
    Friend Function hasstrings() As Boolean
        Return Not _strings Is Nothing
    End Function

    Public Function strings() As strings
        assert(hasstrings(), "do not have stringsPackage defined, or failed to get strings from context.")
        Return _strings
    End Function

    Public Function [string](ByVal stringId As Int64, ByVal ParamArray args() As String) As String
        If args Is Nothing OrElse args.Length() = 0 Then
            Return strings()(stringId)
        Else
            Return String.Format(strings()(stringId), args)
        End If
    End Function

    Public Function formdatas() As map(Of String, formdata)
        Return _formdatas
    End Function

    Public Function formdata(ByVal name As String) As formdata
        If Not formdatas() Is Nothing Then
            Return formdatas(name)
        Else
            Return Nothing
        End If
    End Function

    Public Function cookies() As map(Of String, map(Of String, String))
        Return _cookies
    End Function

    Public Function cookie(ByVal domain As String) As map(Of String, String)
        If Not cookies() Is Nothing Then
            Return cookies(domain)
        Else
            Return Nothing
        End If
    End Function

    Public Function cookie() As map(Of String, String)
        If Not cookies() Is Nothing AndAlso cookies().begin() <> cookies().end Then
            Return (+(cookies().begin())).second
        Else
            Return Nothing
        End If
    End Function

    Public Function rejectIssues() As String
        Return _rejectIssues
    End Function

    Public Function rejectIssuesByte() As Byte
        Return _rejectIssuesByte
    End Function

    Public Function isinternalRequest() As Boolean
        'do not automatically set this value, save sometime for DNS resolving
        If _isinternalRequest = ternary.unknown Then
            If httpUtils.isInternalRequest(localIp(request()), requestIp(), responseIp(request()), url().host()) Then
                _isinternalRequest = ternary.true
            Else
                _isinternalRequest = ternary.false
            End If
        End If
        Return _isinternalRequest = ternary.true
    End Function

    Public Function publicIps() As vector(Of String)
        'do not automatically set this value, save sometime for DNS resolving
        If _publicIps Is Nothing Then
            _publicIps = httpUtils.publicIps(url().host())
        End If
        Return _publicIps
    End Function

    Public Sub close()
        If Not closed() Then
            writer().Flush()
            buff().Flush()
            If buff().Position() > 0 AndAlso response().ContentLength64 = 0 Then
                Try
                    setcontentLength64(buff().Position())
                    response().OutputStream().Write(buff().GetBuffer(), 0, buff().Position())
                Catch ex As Exception
                    raiseError("failed to write data to response outputstream, request " + requestFullUrl(request) + _
                               ", " + ex.Message, errorHandle.errorType.system)
                End Try
            End If
            Try
                closestream(request().InputStream())
                closestream(response().OutputStream())
                response().Close()
            Catch ex As Exception
                raiseError("failed to close response streams, request " + requestFullUrl(request) + _
                           ", " + ex.Message, errorHandle.errorType.system)
            End Try
            buff().Position() = 0
            'do not waste memory for a temporary transfer
            If buff().Capacity() > MAX_BUFF_CAPACITY Then
                buff().SetLength(0)
                buff().Capacity() = MAX_BUFF_CAPACITY
            End If
            _request = Nothing
            _response = Nothing
            _closed = True
        End If
    End Sub

    Private Shared Function traceEvent(ByVal mark As String) As String
        Return character.quoteMark + mark + character.quoteMark
    End Function

    Public Function createControl(ByVal page As webctrl.xhtmlpage) As webctrl.xhtmlpage
        page = createControl(Of webctrl.xhtmlpage)(page)
        assert(Not page Is Nothing)
        page.body().onmousemove += trace.invoke(page.inlineScript(), 5, _
                                                eventMark:=traceEvent(traceEventMark.mousemove)) + ";"
        page.body().onmousedown += trace.invoke(page.inlineScript(), 1, _
                                                eventMark:=traceEvent(traceEventMark.click)) + ";"
        page.body().onkeydown += trace.invoke(page.inlineScript(), 1, _
                                              eventMark:=traceEvent(traceEventMark.keydown)) + ";"
        page.body().increaseInternalAttributes(3)
        Return page
    End Function

    Public Function createControl(Of t As xmlcontrol)(ByVal ctrl As t) As t
        If ctrl Is Nothing Then
            ctrl = alloc(Of t)()
        End If
        If ctrl Is Nothing Then
            'the call GetType(t) uses lots of time
            assert(False, "cannot alloc memory for new xmlcontrol, type " + GetType(t).FullName)
        End If
        ctrl.output = buff()
        Return ctrl
    End Function

    Public Function userInput(ByVal urlName As String, ByVal cookieName As String, ByRef value As String) As Boolean
        value = url().query(urlName)
        If isemptystring(value) AndAlso Not cookie() Is Nothing Then
            value = cookie()(cookieName)
        End If

        Return Not isemptystring(value)
    End Function

    Public Function userInput(ByVal name As String, ByRef value As String) As Boolean
        Return userInput(name, name, value)
    End Function

    Private Sub parseFDHeaders()
        FDRequest.parseheaders(Me)
    End Sub

    Public Sub enableGzip()
        AppRespnose.enableGzip(Me)
    End Sub

    Public Sub disableGzip()
        AppRespnose.disableGzip(Me)
    End Sub

    Private Sub parseUrlencodedInputStream(ByVal action As pointer(Of callbackAction))
        Dim queries As vector(Of pair(Of String, String)) = Nothing
        queries = Nothing
        If Not helper.parseUrlEncodedInputStream(listenerContext(), queries, False,
                                                 action:=action,
                                                 timeoutticks:=MAX_READ_INPUTSTREAM_TIMEOUT_TICKS) Then
            raiseError("get invalid context, " + requestFullUrl(listenerContext()) +
                       ", cannot parse input stream.", errorHandle.errorType.warning)
        Else
            assert(Not queries Is Nothing, "queries is nothing after httpServer.parseInputStream")
            For i = 0 To queries.size() - 1
                If url().query.find(queries(i).first) = url().query.end() Then
                    url().query(queries(i).first) = queries(i).second
                Else
                    url().query(queries(i).first) += character.blank + queries(i).second
                End If
            Next
        End If
    End Sub

    Private Sub parseMultipartInputStream(ByVal action As pointer(Of callbackAction))
        Dim boundary As String = Nothing
        rfc1867.parseContentTypeBoundary(contentType(), boundary)
        rfc1867.parseMultipartInputStream(_formdatas, request().InputStream(), boundary,
                                          action, MAX_READ_INPUTSTREAM_TIMEOUT_TICKS)
    End Sub

    Private Sub parseInputStream(ByVal action As pointer(Of callbackAction))
        If rfc1867.isMultipartFormDataContentType(contentType()) Then
            parseMultipartInputStream(action)
        Else
            parseUrlencodedInputStream(action)
        End If
    End Sub

    Private Function cookieMap(ByVal domain As String, ByVal path As String) As String
        Return domain + network.pathSeperator + path
    End Function

    Private Sub parseCookies()
        If Not request().Cookies Is Nothing Then
            If _cookies Is Nothing Then
                _cookies = New map(Of String, map(Of String, String))()
            End If
            For Each cookie As Cookie In request().Cookies
                If Not cookie Is Nothing Then
                    _cookies(cookieMap(cookie.Domain, cookie.Path))(cookie.Name) = cookie.Value
                End If
            Next
        End If
    End Sub

    'for FDRequest.parseheaders
    Friend Sub setUserAgent(ByVal ua As String)
        copy(_userAgent, ua)
        _isBrowserUserAgent = httpUtils.isBrowserUserAgent(ua)
        _isIEUserAgent = httpUtils.isIEUserAgent(ua)
        _friendlyUserAgent = httpUtils.friendlyUserAgent(ua)
    End Sub

    Private Sub setUserAgent()
        setUserAgent(httpUtils.userAgent(request()))
    End Sub

    'for FDRequest.parseheaders
    Friend Sub setUrl(ByVal s As String)
        url().full = s
        'set a default port if no port information in url, that means user is using default port of http
        If isemptystring(url().port) Then
            url().port = Convert.ToString(network.httpPort)
        End If
        If parameter().parseHttpContextUrlParameters() Then
            Dim it As map(Of String, String).iterator = Nothing
            it = url().query.find(httpContextUrlParameters.language)
            If it <> url().query.end() Then
                setLanguage((+it).second)
            End If
        End If
    End Sub

    Private Sub setUrl()
        setUrl(requestFullUrl(request()))
    End Sub

    Private Sub setAcceptEncoding(ByVal s As String)
        copy(_acceptEncoding, s)
        _acceptGzip = httpUtils.acceptGzip(_acceptEncoding)
    End Sub

    Private Sub setAcceptEncoding()
        setAcceptEncoding(httpUtils.acceptEncoding(request()))
    End Sub

    'for FDRequest.parseheaders
    Friend Sub setReferer(ByVal s As String)
        copy(_referer, s)
        _friendlyReferer = httpUtils.friendlyReferer(s)
    End Sub

    Private Sub setReferer()
        setReferer(httpUtils.referer(request()))
    End Sub

    Private Sub setRequestContentType(ByVal s As String)
        copy(_contentType, s)
    End Sub

    Private Sub setRequestContentType()
        setRequestContentType(httpUtils.contentType(request()))
    End Sub

    'for FDRequest.parseheaders
    Friend Sub setRequestIp(ByVal s As String)
        copy(_requestIp, s)
    End Sub

    Private Sub setRequestIp()
        setRequestIp(httpUtils.requestIp(request()))
    End Sub

    'for FDRequest.parseheaders
    Friend Sub setLanguage(ByVal s As String)
        copy(_language, s)
    End Sub

    Private Sub setLanguage()
        setLanguage(httpUtils.language(request()))
    End Sub

    'for FDRequest.parseheaders
    Friend Sub setTraceID(ByVal s As String)
        copy(_traceID, s)
    End Sub

    Private Sub setTraceID()
        setTraceID(httpUtils.traceID(request()))
    End Sub

    Private Sub setStringsPackage()
        If Not parameter.stringsPackage() Is Nothing Then
            _strings = parameter.stringsPackage(Me)
        Else
            _strings = Nothing
        End If
    End Sub

    Friend Sub setRejectIssues(ByVal rejectIssuesByte As Byte)
        _rejectIssuesByte = rejectIssuesByte
        _rejectIssues = hddoslite.rejectIssues(rejectIssuesByte)
    End Sub

    Public Property listenerContext(Optional ByVal action As pointer(Of callbackAction) = Nothing) _
                                   As HttpListenerContext
        Get
            Return _listenerContext
        End Get
        Set(ByVal value As HttpListenerContext)
            _listenerContext = value
            clearfilters()
            clearformdatas()
            clearCookies()
            clearRejectIssues()
            _isinternalRequest = ternary.unknown
            _publicIps = Nothing
            If _listenerContext Is Nothing Then
                _request = Nothing
                _response = Nothing
                _closed = True
            Else
                _request = _listenerContext.Request
                _response = _listenerContext.Response
                If Not request() Is Nothing AndAlso Not response() Is Nothing Then
                    response().SendChunked() = False
                    response().KeepAlive() = True
                    setcontentEncoding(encoding.utf8)
                    setcontentType(network.http.contentType.texthtmlUtf8)
                    setcontentLength64(0)

                    buff().Position = 0
                    setUserAgent()
                    setReferer()
                    setRequestIp()
                    setLanguage()
                    setTraceID()
                    setAcceptEncoding()
                    setRequestContentType()
                    'there may be some overrides in url, so leave it after others, but before frontdoor headers
                    setUrl()
                    'fd headers are always parsed at the end,
                    'to avoid any changes needed in frontdoor to overwrite url
                    If parameter().parseFDHeaders() Then
                        parseFDHeaders()
                    End If
                    If parameter().parseInputStream() Then
                        parseInputStream(action)
                    End If
                    If parameter().parseCookies() Then
                        parseCookies()
                    End If
                    setStringsPackage()
                    If parameter().enableGzip() Then
                        enableGzip()
                    End If
                    _closed = False
                Else
                    _closed = True
                End If
            End If
        End Set
    End Property

    Public Sub New(Optional ByVal para As parameterDefinition = Nothing)
        If para Is Nothing Then
            _paramter = defaultParameter
        Else
            _paramter = para
        End If
        _url = New url()
        _buff = New MemoryStream()
        _writer = New StreamWriter(_buff, encoding.utf8)
        listenerContext = Nothing
    End Sub

    Protected Overrides Sub Finalize()
        closewriter(_writer)
        GC.KeepAlive(_writer)
        closestream(_buff)
        GC.KeepAlive(_buff)
        MyBase.Finalize()
    End Sub
End Class

Public Class contextPoolDefinition
    Inherits pool(Of httpContext, _true, _false)

    Private Shared HTTPCONTEXT_POOL_LENGTH_COUNTER As Int64
    Private parameter As parameterDefinition = Nothing

    Protected Overrides Function create() As httpContext
        counter.increase(HTTPCONTEXT_POOL_LENGTH_COUNTER)
        Return New httpContext(parameter)
    End Function

    Protected Overrides Sub unalloc(ByRef inst As httpContext)
        If Not inst Is Nothing AndAlso Not inst.closed() Then
            inst.close()
        End If
        counter.decrease(HTTPCONTEXT_POOL_LENGTH_COUNTER)
        MyBase.unalloc(inst)
    End Sub

    Shared Sub New()
        HTTPCONTEXT_POOL_LENGTH_COUNTER = counter.register("HTTPCONTEXT_POOL_LENGTH_COUNTER", 8)
    End Sub

    Public Sub New(Optional ByVal para As parameterDefinition = Nothing)
        Me.New(defaultBuffCount, para)
    End Sub

    Public Sub New(ByVal buffcount As Int64, Optional ByVal para As parameterDefinition = Nothing)
        MyBase.New(buffcount)
        parameter = para
    End Sub
End Class

Public Class contextpool_t
    Inherits pool3(Of httpContext)

    Private parameter As parameterDefinition = Nothing

    Protected Overrides Function create() As httpContext
        Return New httpContext(parameter)
    End Function

    Protected Overrides Sub [erase](ByRef inst As httpContext)
        inst.close()
        MyBase.erase(inst)
    End Sub

    Public Sub New(Optional ByVal para As parameterDefinition = Nothing)
        MyBase.new()
        parameter = para
    End Sub
End Class
